Ezra Vance
Writing

November 18, 2025 6 min read

The hairline problem

A one-pixel border is the most-used component on the web and almost nobody gets it right on a dark background.

Take a divider that looks perfect on a white page, invert the page, and it will be wrong. Not subtly wrong in a way you can argue about — wrong in a way that makes the whole layout feel cheap, in a way most people will notice without being able to name.

Why the inversion fails

On white, a light grey line reads as a fold in paper. Your eye treats it as an absence: the sheet continues, something has been creased. On black, the same relationship produces a line that is brighter than its surroundings, and a bright line on a dark field does not read as a fold. It reads as an edge that has been drawn, or worse, as a light leak.

The fix is not to make it dimmer until it disappears. A line you cannot see is not doing its job either — you get a page of floating fragments with no structure. The fix is to accept that dark-mode hairlines want a different relationship entirely.

What actually works

Three things, in order of how much they matter.

  1. Keep it under 10% away from the canvas. On a near-black background, a line that is more than about a tenth of the way to full brightness stops reading as structure and starts reading as an object. Mine sits at a value only a few percent up from the page.
  2. Give it the canvas's temperature. A neutral grey line on a warm dark background looks blue, which reads as a rendering artefact. Tint the line from the background, not from the text.
  3. Use fewer of them. This is the one that actually fixes most pages. A layout that needs a hairline between every element is a layout with no spacing rhythm, and adding lines is the cheapest possible fix for a problem that whitespace would solve properly.

The device problem

The other half of the problem is that 1px is not one pixel. On a 2x display the browser paints your border across two device pixels and it comes out fine; on some 1.5x and 1.25x Windows and Android displays it lands between them, and the compositor either rounds it to two device pixels — a visibly fat line — or antialiases it to something washed out and inconsistent from row to row.

There is no complete fix for this, only a mitigation: because the line is already very close to the background, an antialiased half-line is a small error rather than an obvious one. A high-contrast hairline makes every rounding artefact visible. A low-contrast hairline forgives the platform.

The test

Screenshot the page, zoom to 400%, and look at the lines. If you can tell which ones landed on a device-pixel boundary and which ones did not, the contrast is too high. Turn it down until they are indistinguishable, then check the whole page still holds its structure. If it collapses without the lines, the lines were never the structure — the spacing was missing all along.

More writing